home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / misc / popen.c < prev    next >
C/C++ Source or Header  |  1996-08-03  |  3KB  |  194 lines

  1. #pragma implementation
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/wait.h>
  5. #include <signal.h>
  6. #include <sys/time.h>
  7. #include <sys/types.h>
  8. #include <unistd.h>
  9. #include "misc.h"
  10. #include "popen.h"
  11.  
  12. PUBLIC POPEN::POPEN(const char *command)
  13. {
  14.     pid = -1;
  15.     status = -1;
  16.     int fdout[2];
  17.     int fderr[2];
  18.     if (pipe(fdout)!=-1 && pipe(fderr)!=-1){
  19.         pid = fork();
  20.         if (pid == 0){
  21.             close (fdout[0]);
  22.             close (fderr[0]);
  23.             dup2 (fdout[1],1);
  24.             dup2 (fderr[1],2);
  25.             close (fdout[1]);
  26.             close (fderr[1]);
  27.             setuid (geteuid());
  28.             int ret = system (command);
  29.             _exit (ret);
  30.         }
  31.         close (fdout[1]);
  32.         close (fderr[1]);
  33.         fds.out = fdout[0];
  34.         fds.err = fderr[0];
  35.     }
  36. }
  37.  
  38. PUBLIC POPEN::~POPEN()
  39. {
  40.     if (pid != -1){
  41.         kill (pid,SIGTERM);
  42.         waitend();
  43.     }
  44.     close (fds.out);
  45.     close (fds.err);
  46. }
  47.  
  48. /*
  49.     Wait until the process is really dead and recover its end status
  50. */
  51. PRIVATE void POPEN::waitend ()
  52. {
  53.     while (1){
  54.         int code = ::wait(&status);
  55.         if (code == pid) break;
  56.         fprintf (stderr,"code = %d\n",code);
  57.     }
  58.     pid = -1;
  59. }
  60.  
  61. /*
  62.     Return != 0 if the pipe is corretly opened
  63. */
  64. PUBLIC int POPEN::isok()
  65. {
  66.     return pid != -1;
  67. }
  68.  
  69. PRIVATE void POPEN::readif (struct fd_set *in, int fd, SSTRING &buf)
  70. {
  71.     if (FD_ISSET(fd,in)){
  72.         char bufread[10000];
  73.         int len = read (fd,bufread,sizeof(bufread)-1);
  74.         if (len > 0){
  75.             bufread[len] = '\0';
  76.             buf.append (bufread);
  77.         }else{
  78.             // end of process
  79.             waitend();
  80.         }
  81.     }
  82. }
  83.  
  84.  
  85. /*
  86.     Wait for anything to be available from the child process
  87.     Return -1 if any error.
  88.     Return  0 if the timeout has elapsed.
  89.     Return  1 if there is some data to read
  90. */
  91. PUBLIC int POPEN::wait(int timeout)
  92. {
  93.     int ret = -1;
  94.     if (pid != -1){
  95.         struct fd_set in;
  96.         FD_ZERO(&in);
  97.         FD_SET (fds.out,&in);
  98.         FD_SET (fds.err,&in);
  99.         struct timeval tim;
  100.         tim.tv_usec = 0;
  101.         tim.tv_sec = timeout;
  102.         int maxfd = fds.err > fds.out ? fds.err : fds.out;
  103.         ret = select (maxfd+1,&in,NULL,NULL,&tim);
  104.         readif (&in,fds.out,outbuf);
  105.         readif (&in,fds.err,errbuf);
  106.     }
  107.     return ret;
  108. }
  109.  
  110. /*
  111.     Return the status code of the ending process
  112. */
  113. PUBLIC int POPEN::getstatus()
  114. {
  115.     return status;
  116. }
  117.  
  118. /*
  119.     Read one complete line or up to size byte in "line".
  120.     If there is no complete line, nothing is read
  121. */
  122. PRIVATE int POPEN::readline (char *line, int size, SSTRING &buf)
  123. {
  124.     char *begin = line;
  125.     const char *pt = buf.get();
  126.     while (1){
  127.         if (*pt == '\0'){
  128.             if (pid == -1){
  129.                 *line = '\0';
  130.                 buf.setfrom ("");
  131.             }else{
  132.                 *begin = '\0';
  133.             }
  134.             break;
  135.         }else{
  136.             char carac = *pt++;
  137.             *line++ = carac;
  138.             size--;
  139.             if (size == 0 || carac == '\n'){
  140.                 buf.setfrom (pt);
  141.                 *line = '\0';
  142.                 break;
  143.             }
  144.         }
  145.     }
  146.     return line > begin ? 0 : -1;
  147. }
  148.  
  149. /*
  150.     Read one line of stderr if available (won't block).
  151. */
  152. PUBLIC int POPEN::readerr (char *line, int size)
  153. {
  154.     return readline (line,size,errbuf);
  155. }
  156. /*
  157.     Read one line of stdout if available (won't block).
  158. */
  159. PUBLIC int POPEN::readout (char *line, int size)
  160. {
  161.     return readline (line,size,outbuf);
  162. }
  163.  
  164. #ifdef TEST
  165.  
  166. int simul_isdemo(){return 0;}
  167. int revision;
  168.  
  169. int main (int argc, char *argv[])
  170. {
  171.     if (argc > 1){
  172.         char buf[1000];
  173.         char *pt = buf;
  174.         for (int i=1; i<argc; i++){
  175.             pt += sprintf (pt,"%s ",argv[i]);
  176.         }
  177.         printf ("execute la commande :%s:\n",buf);
  178.         POPEN p(buf);
  179.         while (p.isok()){
  180.             if (p.wait(10)>0){
  181.                 while (p.readout(buf,sizeof(buf)-1)!=-1){
  182.                     fputs (buf,stdout);
  183.                 }
  184.             }else{
  185.                 break;
  186.             }
  187.         }
  188.     }
  189.     return 0;
  190. }
  191.  
  192. #endif
  193.  
  194.